package com.awesome.common.util.file;

import android.os.Build;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.zip.CRC32;
import java.util.zip.CheckedInputStream;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

import androidx.annotation.RequiresApi;

/**
 * Author: JFangZ
 * Email: janezhang1901@163.com
 * Date: 2020/11/16 15:19
 * Description:文件压缩相关工具类
 */
public class ZipUtil {
    /**
     * Author: JFangZ
     * Email: janezhang1901@163.com
     * Date:2020/11/16 19:37
     * Description:压缩文件夹或者文件
     *
     * @param src             待压缩文件或文件夹
     * @param zipOutputStream 压缩流
     * @param zipEntry        父级目录,压缩文件的相对父级目录
     * @throws IOException
     */
    private static void zip(File src, ZipOutputStream zipOutputStream, ZipEntry zipEntry) throws IOException {
        if (src.isDirectory()) {
            File[] files = src.listFiles();
            // 是文件夹,修改相对父级目录
            zipEntry = new ZipEntry(zipEntry.getName() + src.getName() + File.separator);
            // 添加一个压缩文件夹
            zipOutputStream.putNextEntry(zipEntry);
            if (files == null) {
                return;
            }
            for (File f : files) {
                // 递归遍历子文件夹
                zip(new File(src.getAbsolutePath() + File.separator + f.getName()), zipOutputStream, zipEntry);
            }
        } else {
            // 根据相对父级目录创建一个新文件
            zipOutputStream.putNextEntry(new ZipEntry(zipEntry.getName() + src.getName()));
            FileInputStream fileInputStream = new FileInputStream(src);
            byte[] bytes = new byte[1024];
            int len;
            while ((len = fileInputStream.read(bytes)) != -1) {
                zipOutputStream.write(bytes, 0, len);
            }
            zipOutputStream.flush();
            fileInputStream.close();
        }
    }

    /**
     * Author: JFangZ
     * Email: janezhang1901@163.com
     * Date:2020/11/16 19:37
     * Description:压缩
     *
     * @param src 待压缩文件或文件夹
     * @param dst 压缩后生成的文件
     * @return true 压缩成功,false 压缩失败
     */
    public static boolean zip(File src, File dst) {
        if (dst.getParentFile() != null) {
            dst.getParentFile().mkdirs();
        }
        ZipOutputStream zipOutputStream = null;
        try {
            zipOutputStream = new ZipOutputStream(new CheckedOutputStream(new FileOutputStream(dst), new CRC32()));
            zip(src, zipOutputStream, new ZipEntry(""));
            return true;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (zipOutputStream != null) {
                try {
                    zipOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }

    /**
     * Author: JFangZ
     * Email: janezhang1901@163.com
     * Date:2020/11/16 20:08
     * Description:解压缩
     *
     * @param src 压缩包
     * @param dst 解压后目录
     * @return true 解压缩成功,false 解压缩失败
     */
    public static boolean unzip(File src, File dst) {
        if (dst.getParentFile() != null) {
            dst.getParentFile().mkdirs();
        }
        ZipInputStream zipInputStream = null;
        FileOutputStream fileOutputStream = null;
        try {
            ZipFile zipFile = new ZipFile(src);
            zipInputStream = new ZipInputStream(new CheckedInputStream(new FileInputStream(src), new CRC32()));
            ZipEntry zipEntry;
            while ((zipEntry = zipInputStream.getNextEntry()) != null) {
                if (zipEntry.isDirectory()) {
                    // 是文件夹则创建文件夹
                    new File(dst.getAbsolutePath() + File.separator + zipEntry.getName()).mkdirs();
                } else {
                    // 是文件则读取文件
                    try {
                        fileOutputStream = new FileOutputStream(dst.getAbsolutePath() + File.separator + zipEntry.getName());
                    } catch (FileNotFoundException e) {
                        continue;
                    }
                    InputStream inputStream = zipFile.getInputStream(zipEntry);
                    byte[] bytes = new byte[1024];
                    int len = 0;
                    while ((len = inputStream.read(bytes)) != -1) {
                        fileOutputStream.write(bytes, 0, len);
                    }
                    fileOutputStream.flush();
                    inputStream.close();
                }
            }
            return true;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                return unzip(src, dst, Charset.forName("GBK"));
            }
        } finally {
            if (zipInputStream != null) {
                try {
                    zipInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }

    /**
     * Author: JFangZ
     * Email: janezhang1901@163.com
     * Date:2020/11/16 20:08
     * Description:解压缩
     *
     * @param src     压缩包
     * @param dst     解压后目录
     * @param charset 指定字符集
     * @return true 解压缩成功,false 解压缩失败
     */
    @RequiresApi(api = Build.VERSION_CODES.N)
    public static boolean unzip(File src, File dst, Charset charset) {
        if (dst.getParentFile() != null) {
            dst.getParentFile().mkdirs();
        }
        ZipInputStream zipInputStream = null;
        FileOutputStream fileOutputStream = null;
        try {
            ZipFile zipFile = new ZipFile(src, charset);
            zipInputStream = new ZipInputStream(new CheckedInputStream(new FileInputStream(src), new CRC32()), charset);
            ZipEntry zipEntry;
            while ((zipEntry = zipInputStream.getNextEntry()) != null) {
                if (zipEntry.isDirectory()) {
                    // 是文件夹则创建文件夹
                    new File(dst.getAbsolutePath() + File.separator + zipEntry.getName()).mkdirs();
                } else {
                    // 是文件则读取文件
                    try {
                        fileOutputStream = new FileOutputStream(dst.getAbsolutePath() + File.separator + zipEntry.getName());
                    } catch (FileNotFoundException e) {
                        continue;
                    }
                    InputStream inputStream = zipFile.getInputStream(zipEntry);
                    byte[] bytes = new byte[1024];
                    int len = 0;
                    while ((len = inputStream.read(bytes)) != -1) {
                        fileOutputStream.write(bytes, 0, len);
                    }
                    fileOutputStream.flush();
                    inputStream.close();
                }
            }
            return true;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (zipInputStream != null) {
                try {
                    zipInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }
}
